package org.dreamwork.seagragon;

import org.dreamwork.misc.AlgorithmUtil;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionContext;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by IntelliJ IDEA.
 * User: seth.yang
 * Date: 2010-7-8
 * Time: 13:40:25
 */
public class ImitationHttpSession implements HttpSession {
    private long creationTime, lastAccessedTime;
    private String id;
    private ServletContext context;
    private Map<String, Object> attributes = new HashMap<String, Object> ();
    private boolean visited = false;

    private static final List<HttpSessionAttributeListener> listeners = new ArrayList<HttpSessionAttributeListener> ();
    private static final Map<String, HttpSession> pool = new ConcurrentHashMap<String, HttpSession> (0);

    static HttpSession findSessionById (String id) {
        return pool.get (id);
    }

    public static void addListener (HttpSessionAttributeListener l) {
        synchronized (listeners) {
            listeners.add (l);
        }
    }

    ImitationHttpSession (ServletContext context) {
        creationTime = System.currentTimeMillis ();
        lastAccessedTime = System.currentTimeMillis ();
        this.context = context;
        try {
            id = AlgorithmUtil.md5 (String.valueOf (Math.random () * Math.random ()));
        } catch (Exception e) {
            throw new RuntimeException ("internal error!");
        }

        synchronized (pool) {
            pool.put (id, this);
        }
    }

    public long getCreationTime () {
        return creationTime;
    }

    public String getId () {
        return id;
    }

    public long getLastAccessedTime () {
        return lastAccessedTime;
    }

    public ServletContext getServletContext () {
        touch ();
        return context;
    }

    public void setMaxInactiveInterval (int i) {

    }

    public int getMaxInactiveInterval () {
        return -1;
    }

    @Deprecated
    public HttpSessionContext getSessionContext () {
        return null;
    }

    public Object getAttribute (String s) {
        touch ();
        return attributes.get (s);
    }

    @Deprecated
    public Object getValue (String s) {
        return getAttribute (s);
    }

    public Enumeration getAttributeNames () {
        touch ();
        return new ReadOnlyEnumeration (attributes.keySet ());
    }

    @Deprecated
    public String[] getValueNames () {
        touch ();
        return attributes.keySet ().toArray (new String[attributes.size ()]);
    }

    public void setAttribute (String s, Object o) {
        visited = true;
        Object x = attributes.get (s);
        if (x == null) {
            attributes.put (s, o);
            for (HttpSessionAttributeListener l : listeners) {
                l.attributeAdded (new HttpSessionBindingEvent (this, s, o));
            }
        } else if (!x.equals (o)) {
            attributes.put (s, o);
            for (HttpSessionAttributeListener l : listeners) {
                l.attributeReplaced (new HttpSessionBindingEvent (this, s, o));
            }
        }
    }

    @Deprecated
    public void putValue (String s, Object o) {
        setAttribute (s, o);
    }

    public void removeAttribute (String s) {
        touch ();
        Object o = attributes.remove (s);
        for (HttpSessionAttributeListener l : listeners) {
            l.attributeRemoved (new HttpSessionBindingEvent (this, s, o));
        }
    }

    @Deprecated
    public void removeValue (String s) {
        removeAttribute (s);
    }

    public void invalidate () {
        touch ();
        attributes.clear ();
    }

    public boolean isNew () {
        return !visited;
    }

    private void touch () {
        visited = true;
        lastAccessedTime = System.currentTimeMillis ();
    }
}